import chardet

class FileReader:
    @staticmethod
    def read(file_path, mode='r', encoding=None, fallback_encodings=None, 
             errors='strict', auto_fallback=False):
        """
        读取文件内容，自动处理编码问题。
        
        :param file_path: 文件路径
        :param mode: 打开模式，默认为 'r'（文本模式）
        :param encoding: 指定编码，如果提供，则优先使用该编码
        :param fallback_encodings: 备选编码列表，默认包含常见编码
        :param errors: 解码错误处理方式，默认为 'strict'
        :param auto_fallback: 当指定编码时，解码失败后尝试备选编码，默认为 False
        :return: 文件内容字符串或字节
        """
        if 'b' in mode:
            with open(file_path, mode) as f:
                return f.read()
        else:
            if encoding and not auto_fallback:
                try:
                    with open(file_path, mode, encoding=encoding, errors=errors) as f:
                        return f.read()
                except UnicodeDecodeError as e:
                    raise UnicodeDecodeError(
                        f"无法用编码 '{encoding}' 解码文件 '{file_path}'，错误信息：{e}"
                    ) from e

            with open(file_path, 'rb') as f:
                raw_data = f.read()

            detected_encoding = FileReader.detect_encoding(raw_data)
            fallback_encodings = fallback_encodings or ['utf-8', 'gbk', 'gb18030', 'big5', 'latin-1']
            
            encodings_to_try = []
            if encoding and auto_fallback:
                encodings_to_try.append(encoding)
            if detected_encoding:
                encodings_to_try.append(detected_encoding)
            encodings_to_try.extend(fallback_encodings)

            seen = set()
            unique_encodings = []
            for enc in encodings_to_try:
                if enc and enc not in seen:
                    seen.add(enc)
                    unique_encodings.append(enc)
            for enc in ['utf-8', 'gbk', 'latin-1']:
                if enc not in seen:
                    unique_encodings.append(enc)

            for enc in unique_encodings:
                try:
                    return raw_data.decode(enc, errors=errors)
                except UnicodeDecodeError:
                    continue

            raise UnicodeDecodeError(
                f"无法解码文件 '{file_path}'，已尝试编码：{unique_encodings}"
            )

    @staticmethod
    def detect_encoding(data, chunk_size=4096):
        chunk = data[:chunk_size] if len(data) >= chunk_size else data
        try:
            result = chardet.detect(chunk)
            if result['confidence'] > 0.5:
                return result['encoding']
            return None
        except Exception:
            return None

    @staticmethod
    def read_bytes(file_path):
        """读取文件的二进制内容"""
        with open(file_path, 'rb') as f:
            return f.read()